<?php
###
#  Baing PHP 框架 1.0.0
#  http://baing.co/
#
#  Copyright: 白晓阳
#  License: CC BY-NC-SA 4.0
#  https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh
###

namespace bai\resource\application;

use bai\feature\RuntimeException, bai\feature\ResourceException, bai\feature\ExtensionException;


/**
 * <cURL>
 * Runtime
 * [
 *     'url' => 'url'
 *     'method' => 'method'
 *     'headers' => 'headers'
 *     'cookies' => 'headers'
 *     'body' => 'body'
 * ]
 */
class HttpService extends \bai\resource\Application
{
    private const EXTENSION = 'cURL';

    protected static function setupId(array &$runtime, string $key = ''): string
    {
        return parent::setupId($runtime, $runtime['url'] ?? $key);
    }

    public function run(array $runtime = [])
    {
        $access = $this->find('access');

        $method = $runtime['method'] ?? $this->find('method') ?? self::GET;
        curl_setopt($access, CURLOPT_CUSTOMREQUEST, $method);

        $headers = $runtime['headers'] ?? $this->find('headers') ?? [];
        if ($headers && !isset($headers[0])) {
            $content = [];
            foreach ($headers as $key => $value) {
                $content[] = "$key: $value";
            }
            $headers = $content;
        }
        curl_setopt($access, CURLOPT_HTTPHEADER, $headers);

        $cookies = $runtime['cookies'] ?? $this->find('cookies') ?? '';
        if (is_array($cookies)) {
            $content = [];
            foreach ($cookies as $key => $value) {
                $content[] = "$key=$value";
            }
            $cookies = implode(';', $content);
        }
        curl_setopt($access, CURLOPT_COOKIE, $cookies);

        curl_setopt($access, CURLOPT_POSTFIELDS, $runtime['body'] ?? $this->find('body') ?? '');

        $result = curl_exec($access);
        return [
            'status' => $result !== false ? self::SUCCEEDED : self::FAILED,
            'result' => $result
        ];
    }

    protected function init()
    {
        if (!extension_loaded(self::EXTENSION)) {
            throw new ExtensionException(self::EXTENSION);
        }
        
        $url = $this->find('url');
        if (!$url) {
            throw new RuntimeException('url');
        }

        $this->runtime['access'] = $access = curl_init($url);
        if (!$access) {
            throw new ResourceException(params: $url);
        }
        $this->setupOptions();
    }

    protected function close()
    {
        if ($access = $this->find('access')) {
            curl_close($access);
        }
        parent::close();
    }

    protected function setupOptions()
    {
        $access = $this->find('access');
        curl_setopt($access, CURLOPT_CONNECTTIMEOUT, $this->find('connectTimeout') ?? 6);
        curl_setopt($access, CURLOPT_TIMEOUT, $this->find('timeout') ?? 30);
        curl_setopt($access, CURLOPT_MAXREDIRS, 10);
        curl_setopt($access, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($access, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($access, CURLOPT_HEADER, false);
    }
}